import { ref } from 'vue'
import workerSrc from 'pdfjs-dist/build/pdf.worker.min.js?url'
import { GlobalWorkerOptions,getDocument } from 'pdfjs-dist'

GlobalWorkerOptions.workerSrc = workerSrc



function loadLodopScript(protocol = 'http', host = 'localhost', port = 8000) {
  return new Promise((resolve, reject) => {
    const scriptId = `lodop-script-${protocol}-${host}-${port}`
    const existing = document.getElementById(scriptId)
    if (existing) return resolve()

    const script = document.createElement('script')
    script.id = scriptId
    script.src =
      protocol === 'https'
        ? 'https://localhost.lodop.net:8443/CLodopfuncs.js'
        : `http://${host}:${port}/CLodopfuncs.js`

    script.onload = () => {
      setTimeout(() => {
        if (typeof window.getCLodop === 'function') {
          resolve()
        } else {
          reject('getCLodop 函数未挂载')
        }
      }, 0)
    }

    script.onerror = () => reject(`加载失败: ${script.src}`)
    document.head.appendChild(script)
  })
}

function base64ToBlobUrl(base64pdf) {
  if (base64pdf.startsWith('data:application/pdf;base64,')) {
    base64pdf = base64pdf.replace('data:application/pdf;base64,', '')
  }
  const byteCharacters = atob(base64pdf)
  const byteNumbers = Array.from(byteCharacters, char => char.charCodeAt(0))
  const byteArray = new Uint8Array(byteNumbers)
  const blob = new Blob([byteArray], { type: 'application/pdf' })
  return URL.createObjectURL(blob)
}


export function createLodopInstance(protocol = 'http', host = 'localhost', port = 8000) {
  const lodopReady = ref(false)
  const lodopError = ref(null)
  const lodopRef = ref(null)

  const initLodop = async () => {
    lodopReady.value = false
    lodopError.value = null

    try {
      await loadLodopScript(protocol, host, port)
      const getLodop = window.getCLodop
      const lodop = getLodop()
      if (!lodop || typeof lodop.VERSION === 'undefined') {
        throw new Error('LODOP 服务未启动或版本获取失败')
      }

      lodop.SET_LICENSES('', '78DAA88C64871619EF65E45BB1247520353', '', '')
      lodopRef.value = lodop
      lodopReady.value = true
    } catch (error) {
      lodopError.value = error.toString()
    }
  }

  const getLodopInstance = () => lodopRef.value

  const printHtml = (html, printIndex, printTask) => {
    const LODOP = getLodopInstance()
    if (!LODOP) return alert('LODOP 未就绪')
    LODOP.PRINT_INIT(printTask || '打印任务')
    LODOP.SET_PRINTER_INDEX(printIndex)
    LODOP.ADD_PRINT_HTM(0, 0, '100%', '100%', html)
    LODOP.PRINT()
  }

  const printPdfUrl = (pdfUrl, printIndex, printTask) => {
    const LODOP = getLodopInstance()
    if (!LODOP) return alert('LODOP 未就绪')
    LODOP.PRINT_INIT(printTask || '打印任务')
    LODOP.SET_PRINTER_INDEX(printIndex)
    LODOP.ADD_PRINT_PDF(0, 0, '100%', '100%', pdfUrl)
    LODOP.PRINT()
  }

  const printPdfBase64 = (base64pdf, printIndex, printTask) => {

    const LODOP = getLodopInstance()
    if (!LODOP) return alert('LODOP 未就绪')
    LODOP.PRINT_INIT(printTask || '打印任务')
    LODOP.SET_PRINTER_INDEX(printIndex)
    LODOP.SET_PRINT_MODE("PRINT_DIRECTLY", true);

    LODOP.SET_PRINT_MODE("PDF_PRINT_PAGE_TYPE", "Auto");



    LODOP.ADD_PRINT_PDF(0, 0, '100%', '100%', removeBasePrefix(base64pdf))




    LODOP.PRINT()


  }

const printImageBase64 = (base64pdf, printIndex, printTask) => {
    const LODOP = getLodopInstance()
    if (!LODOP) return alert('LODOP 未就绪')
    LODOP.PRINT_INIT(printTask || '打印任务')
    LODOP.SET_PRINTER_INDEX(printIndex)
    LODOP.ADD_PRINT_IMAGE(0, 0, '100%', '100%', removeBasePrefix(base64pdf))
    LODOP.PRINT()
  }



  const getPrinters = () => {
    const LODOP = getLodopInstance()
    const list = []
    try {
      const count = LODOP?.GET_PRINTER_COUNT?.() || 0
      for (let i = 0; i < count; i++) {
        list.push({
          name: LODOP.GET_PRINTER_NAME(i),
          index: i,
        })
      }
    } catch (e) {
      console.warn('获取打印机列表失败', e)
    }
    return list
  }


async function printPdfFromUrlAsBase64(url, printIndex, printTask) {
  try {
    // 1. 下载 PDF 文件
    const response = await fetch(url);
    if (!response.ok) throw new Error('下载失败');

    const blob = await response.blob();

    // 2. 转换为 base64
    let base64 = await blobToBase64(blob);

    base64 = removeBasePrefix(base64)
    // 3. 使用 LODOP 打印 base64 PDF
    const LODOP = getLodopInstance()
    if (!LODOP) return alert('LODOP 未就绪')
    LODOP.PRINT_INIT(printTask || '打印任务')
    LODOP.SET_PRINTER_INDEX(printIndex)
    LODOP.ADD_PRINT_PDF(0, 0, "100%", "100%", base64)
    LODOP.PRINT()  // 或 PRINT()
  } catch (err) {
    console.error('打印失败:', err);
  }
}



function blobToBase64(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result); // 返回 base64 string
    reader.onerror = reject;
    reader.readAsDataURL(blob);
  });
}


function removeBasePrefix(data){
  return data.replace(/^data:.*;base64,/, '')
}



  /**
   * 根据用户输入纸张尺寸和dpi打印PDF base64（高清渲染图片）
   * @param {string} base64pdf - PDF的base64字符串
   * @param {number} printIndex - 打印机索引
   * @param {number} paperWidthMm - 纸张宽度，单位 mm
   * @param {number} paperHeightMm - 纸张高度，单位 mm
   * @param {number} dpi - 打印机DPI，通常300或600
   * @param {string} printTask - 打印任务名
   */
  async function printPdfWithUserSize(base64pdf, printIndex, paperWidthMm, paperHeightMm, dpi = 300, printTask = '打印任务') {
    // 获取 LODOP 实例
    const LODOP = getLodopInstance();
    if (!LODOP) throw new Error('LODOP 未就绪');

    // 去除 base64 前缀
    const base64Data = base64pdf.includes('base64,') ? base64pdf.split('base64,')[1] : base64pdf;

    // base64 解码为 Uint8Array（二进制流）
    const raw = atob(base64Data);
    const pdfData = new Uint8Array(raw.length);
    for (let i = 0; i < raw.length; i++) {
      pdfData[i] = raw.charCodeAt(i);
    }

    // 用 pdfjs-dist 加载 PDF 文档
    const pdf = await getDocument({ data: pdfData }).promise;
    const pageCount = pdf.numPages; // 获取总页数

    // 初始化 LODOP 打印任务
    LODOP.PRINT_INIT(printTask);
    LODOP.SET_PRINTER_INDEX(printIndex); // 设置打印机索引


    // 将纸张尺寸从 mm 转换为像素（DPI 决定精度）
    const targetWidthPx = (paperWidthMm / 25.4) * dpi;
    const targetHeightPx = (paperHeightMm / 25.4) * dpi;

    for (let pageNum = 1; pageNum <= pageCount; pageNum++) {
      // 获取每一页
      const page = await pdf.getPage(pageNum);



      // 获取 PDF 页面原始大小（单位：pt，1pt ≈ 1/72英寸）
      const viewport0 = page.getViewport({ scale: 1.0 });

      // 计算缩放比例，使页面刚好适配打印尺寸
      const scaleX = targetWidthPx / viewport0.width;
      const scaleY = targetHeightPx / viewport0.height;
      const scale = Math.min(scaleX, scaleY) ;

      // 按比例缩放 viewport
      const viewport = page.getViewport({ scale });

      // 创建高分辨率 canvas
      const canvas = document.createElement('canvas');
      canvas.width = Math.floor(viewport.width);
      canvas.height = Math.floor(viewport.height);

      const ctx = canvas.getContext('2d');
      // 开启图像抗锯齿
      ctx.imageSmoothingEnabled = true;
      ctx.imageSmoothingQuality = 'high';


      // ctx.fillStyle = 'white';
      // ctx.fillRect(0, 0, canvas.width, canvas.height);

      // 将 PDF 页面渲染到 canvas 上
      await page.render({ canvasContext: ctx, viewport }).promise;

      // 将 canvas 转为 base64 图片（用于 LODOP 打印）
      const imgData = canvas.toDataURL('image/png');

      // 添加打印图片，单位为 mm，确保纸张尺寸与预期一致
      LODOP.ADD_PRINT_IMAGE("0mm", "0mm", `${paperWidthMm}mm`, `${paperHeightMm}mm`, imgData);
      LODOP.SET_PRINT_STYLEA(0, "Stretch", 2); // 自动等比缩放填充区域

      // 多页处理：除了最后一页都添加新页
      if (pageNum < pageCount) {
        LODOP.NewPage();
      }
    }

    // 开始打印（你也可以改为 PREVIEW 预览）
    LODOP.PRINT();
  }

  // mm → px
  const mmToPx = (mm, dpi) => Math.round((mm / 25.4) * dpi);


  /**
   * 将 base64 PDF 渲染成 ESC/POS 打印指令
   * @param {string} base64pdf PDF base64（可带 data: 前缀）
   * @param {number} paperWidthMm 纸张宽度 mm
   * @param {number} paperHeightMm 纸张高度 mm
   * @param {number} dpi 分辨率（默认 203，适合热敏机）
   * @returns {Promise<Uint8Array>} ESC/POS 字节指令
   */
  async function pdfToEscposCommands(base64pdf, paperWidthMm = 58, paperHeightMm = 40, dpi = 203) {
// 去除 base64 前缀
    const base64Data = base64pdf.includes('base64,') ? base64pdf.split('base64,')[1] : base64pdf;

    // 解码为 Uint8Array
    const binary = atob(base64Data);
    const pdfData = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      pdfData[i] = binary.charCodeAt(i);
    }

    // 加载 PDF 文档
    const pdf = await getDocument({ data: pdfData }).promise;
    const pageCount = pdf.numPages;
    const escposPages = [];

    // 计算纸张像素尺寸
    const targetWidthPx = (paperWidthMm / 25.4) * dpi;
    const targetHeightPx = (paperHeightMm / 25.4) * dpi;

    for (let pageNum = 1; pageNum <= pageCount; pageNum++) {
      const page = await pdf.getPage(pageNum);

      // 获取原始页面大小
      const viewport0 = page.getViewport({ scale: 1.0 });

      // 缩放比例适配目标尺寸
      const scale = Math.min(targetWidthPx / viewport0.width, targetHeightPx / viewport0.height);
      const viewport = page.getViewport({ scale });

      // 创建 canvas 渲染 PDF
      const canvas = document.createElement('canvas');
      canvas.width = Math.floor(viewport.width);
      canvas.height = Math.floor(viewport.height);

      const ctx = canvas.getContext('2d');
      ctx.imageSmoothingEnabled = true;
      ctx.imageSmoothingQuality = 'high';

      await page.render({ canvasContext: ctx, viewport }).promise;

      // 获取像素数据
      const { data, width, height } = ctx.getImageData(0, 0, canvas.width, canvas.height);

      // ESC/POS 图像行每行字节数（1 bit/pixel）
      const bytesPerLine = Math.ceil(width / 8);
      const escpos = [];

      // 添加 ESC/POS 图像打印头部命令: GS v 0
      escpos.push(0x1D, 0x76, 0x30, 0x00);
      escpos.push(bytesPerLine & 0xFF, (bytesPerLine >> 8) & 0xFF); // width (xL, xH)
      escpos.push(height & 0xFF, (height >> 8) & 0xFF);             // height (yL, yH)

      // 逐行逐列生成 ESC/POS 位图数据
      for (let y = 0; y < height; y++) {
        for (let xByte = 0; xByte < bytesPerLine; xByte++) {
          let byte = 0;
          for (let bit = 0; bit < 8; bit++) {
            const x = xByte * 8 + bit;
            if (x >= width) continue;

            const pixelIndex = (y * width + x) * 4;
            const r = data[pixelIndex];
            const g = data[pixelIndex + 1];
            const b = data[pixelIndex + 2];

            const gray = 0.3 * r + 0.59 * g + 0.11 * b;
            const pixel = gray < 128 ? 1 : 0;

            byte |= pixel << (7 - bit);
          }
          escpos.push(byte);
        }
      }

      escposPages.push(new Uint8Array(escpos));
    }

    return escposPages; // 每页一段 Uint8Array 指令
  }

  async function pdfToZplPagesArray(base64pdf, paperWidthMm, paperHeightMm, dpi = 203,  offsetX = 0, offsetY = 0,threshold = 128) {
    const base64Data = base64pdf.includes('base64,') ? base64pdf.split('base64,')[1] : base64pdf;
    const raw = atob(base64Data);
    const pdfData = new Uint8Array(raw.length);
    for (let i = 0; i < raw.length; i++) {
      pdfData[i] = raw.charCodeAt(i);
    }

    const pdf = await getDocument({ data: pdfData }).promise;
    console.log('PDF 总页数:', pdf.numPages);
    const pageCount = pdf.numPages;

    const targetWidthPx = Math.floor((paperWidthMm / 25.4) * dpi);
    const targetHeightPx = Math.floor((paperHeightMm / 25.4) * dpi);

    const zplPages = [];

    for (let pageNum = 1; pageNum <= pageCount; pageNum++) {
      console.log('渲染第', pageNum, '页');
      const page = await pdf.getPage(pageNum);

      const viewport0 = page.getViewport({ scale: 1.0 });
      const scaleX = targetWidthPx / viewport0.width;
      const scaleY = targetHeightPx / viewport0.height;
      const scale = Math.min(scaleX, scaleY);

      const viewport = page.getViewport({ scale });

      const renderCanvas = document.createElement('canvas');
      renderCanvas.width = Math.floor(viewport.width);
      renderCanvas.height = Math.floor(viewport.height);

      const renderCtx = renderCanvas.getContext('2d');
      renderCtx.imageSmoothingEnabled = true;
      renderCtx.imageSmoothingQuality = 'high';

      await page.render({ canvasContext: renderCtx, viewport }).promise;

      const canvas = document.createElement('canvas');
      canvas.width = targetWidthPx;
      canvas.height = targetHeightPx;

      const ctx = canvas.getContext('2d');
      ctx.fillStyle = '#FFFFFF';
      ctx.fillRect(0, 0, canvas.width, canvas.height);

      const dx = (canvas.width - renderCanvas.width) / 2 + offsetX;
      const dy = (canvas.height - renderCanvas.height) / 2 + offsetY;

      ctx.drawImage(renderCanvas, dx, dy);

      const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);
      const width = canvas.width;
      const height = canvas.height;
      const bytesPerRow = Math.ceil(width / 8);
      const totalBytes = bytesPerRow * height;
      const monoImage = new Uint8Array(totalBytes);

      for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
          const i = (y * width + x) * 4;
          const r = data[i], g = data[i + 1], b = data[i + 2];
          const gray = 0.299 * r + 0.587 * g + 0.114 * b;
          if (gray < threshold) {
            monoImage[y * bytesPerRow + (x >> 3)] |= 0x80 >> (x % 8);
          }
        }
      }

      const hexData = Array.from(monoImage)
          .map(b => b.toString(16).toUpperCase().padStart(2, '0'))
          .join('');

      const zpl = `^XA
^FO0,0
^GFA,${totalBytes},${totalBytes},${bytesPerRow},${hexData}
^XZ`;

      zplPages.push(zpl);
    }

    console.log('生成 ZPL 页数:', zplPages.length);

    return zplPages;
  }

//   async function pdfToZplPagesArray(base64pdf, paperWidthMm, paperHeightMm, dpi = 203, threshold = 128) {
//     const base64Data = base64pdf.includes('base64,') ? base64pdf.split('base64,')[1] : base64pdf;
//     const raw = atob(base64Data);
//     const pdfData = new Uint8Array(raw.length);
//     for (let i = 0; i < raw.length; i++) {
//       pdfData[i] = raw.charCodeAt(i);
//     }
//
//     const pdf = await getDocument({ data: pdfData }).promise;
//
//     const targetWidthPx = Math.floor((paperWidthMm / 25.4) * dpi);
//     const targetHeightPx = Math.floor((paperHeightMm / 25.4) * dpi);
//
//     const zplPages = [];
//
//     for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
//       const page = await pdf.getPage(pageNum);
//
//       const viewport0 = page.getViewport({ scale: 1.0 });
//       const scale = Math.min(targetWidthPx / viewport0.width, targetHeightPx / viewport0.height);
//       const viewport = page.getViewport({ scale });
//
//       const canvas = document.createElement('canvas');
//       canvas.width = Math.max(Math.floor(viewport.width), 1);
//       canvas.height = Math.max(Math.floor(viewport.height), 1);
//       const ctx = canvas.getContext('2d');
//       ctx.imageSmoothingEnabled = true;
//       ctx.imageSmoothingQuality = 'high';
//
//       await page.render({ canvasContext: ctx, viewport }).promise;
//
//       const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
//       const { data } = imageData;
//
//       const width = canvas.width;
//       const height = canvas.height;
//       const bytesPerRow = Math.ceil(width / 8);
//       const totalBytes = bytesPerRow * height;
//
//       const mono = new Uint8Array(totalBytes);
//
//       for (let y = 0; y < height; y++) {
//         for (let x = 0; x < width; x++) {
//           const i = (y * width + x) * 4;
//           const r = data[i], g = data[i + 1], b = data[i + 2];
//           const gray = 0.299 * r + 0.587 * g + 0.114 * b;
//           if (gray < threshold) {
//             mono[y * bytesPerRow + (x >> 3)] |= (0x80 >> (x % 8));
//           }
//         }
//       }
//
//       const hexLines = [];
//       for (let i = 0; i < mono.length; i++) {
//         hexLines.push(mono[i].toString(16).toUpperCase().padStart(2, '0'));
//       }
//       const hexData = hexLines.join('');
//
//       const zpl = `^XA
// ^FO0,0
// ^GFA,${totalBytes},${totalBytes},${bytesPerRow},${hexData}
// ^XZ`;
//
//       zplPages.push(zpl);
//     }
//
//     return zplPages;
//   }


  async function printBase64PdfForZpl( base64Pdf, printerName, paperWidthMm = 101, paperHeightMm = 154  ,dpi = 203, offsetX, offsetY){
    const LODOP = getLodopInstance();
    if (!LODOP) throw new Error('LODOP 未就绪');
    const zplArray = await pdfToZplPagesArray(base64Pdf, paperWidthMm,paperHeightMm, dpi,offsetX,offsetY);
    LODOP.SET_PRINTER_INDEX(printerName);
    zplArray.map((value,index) =>{
      LODOP.SET_PRINT_MODE("SEND_RAW_DATA_ENCODE","UTF-8");
      LODOP.SEND_PRINT_RAWDATA(value)
    })
  }


  /**
   * 发送 ESC/POS 指令到打印机（通过 LODOP）
   * @param {Object} options
   * @param {string} options.base64Pdf - base64 编码的 PDF 数据（仅第一页）
   * @param {string} options.printerName - 打印机名称（必须完全匹配系统打印机名）
   * @param {number} options.dpi - 打印分辨率，推荐 203
   * @param {number} options.paperWidthMm - 标签宽度（单位 mm）
   * @param {number} options.paperHeightMm - 标签高度（单位 mm）
   */
   async function sendEscposToPrinterViaLodop( base64Pdf, printerName, dpi = 203, paperWidthMm = 101, paperHeightMm = 154 ) {
    const LODOP = getLodopInstance();
    if (!LODOP) throw new Error('LODOP 未就绪');
    // 生成 ESC/POS 指令
    const escposBytes = await pdfToEscposCommands(base64Pdf,  paperWidthMm, paperHeightMm,dpi);
    LODOP.SET_PRINTER_INDEX(printerName);
    escposBytes.map((value, index) => {
      const strData = Array.from(value).map(b => String.fromCharCode(b)).join("")
      LODOP.SET_PRINT_MODE('SEND_RAW_DATA_ENCODE', 'EXT-ASCII')
      LODOP.SEND_PRINT_RAWDATA(strData)
    })
  }



  return {
    initLodop,
    lodopReady,
    lodopError,
    printHtml,
    printPdfUrl,
    printPdfBase64,
    getPrinters,
    createLodopInstance,
    printPdfFromUrlAsBase64,
    printPdfWithUserSize,
    sendEscposToPrinterViaLodop,
    printBase64PdfForZpl
  }
}
